import cv2
import numpy as np
import matplotlib.pyplot as plt
from PIL import Image
import os

plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']  # 设置字体为微软雅黑

source_img = cv2.imread('C:/Users/hp/Desktop/1.jpg')  # 使用cv2打开源图像
gray_img = cv2.cvtColor(source_img, cv2.COLOR_BGR2GRAY)  # 使用cv2将源图像转换为灰度图
threshold_val = 128  # 设定阈值

# 使用cv2.threshold将灰度图转换为二值图
_, binary_img = cv2.threshold(gray_img, threshold_val, 255, cv2.THRESH_BINARY)

# 使用cv2.bitwise_not来实现黑白颜色的互换
binary_img = cv2.bitwise_not(binary_img)

# 将二值图转换为numpy数组以便使用opencv处理
opencv_img = np.array(binary_img)
# 定义结构元素
structuring_element = np.ones((3, 3), np.uint8)  
# 使用腐蚀操作
eroded_img = cv2.erode(opencv_img, structuring_element, iterations=4)  
# 使用膨胀操作
dilated_img = cv2.dilate(eroded_img, structuring_element, iterations=8)  
# 使用中值滤波
filtered_img = cv2.medianBlur(dilated_img, 27)  
# 使用闭运算
closed_img = cv2.morphologyEx(filtered_img, cv2.MORPH_CLOSE, structuring_element, iterations=50)  
# 使用高斯模糊
blurred_img = cv2.GaussianBlur(closed_img, (3,3), 0)  

# 使用Canny边缘检测，手动定义上下阈值
lower = 50
upper = 200
edges_detected = cv2.Canny(blurred_img, lower, upper)

# 寻找轮廓
contours, _ = cv2.findContours(edges_detected, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

img_with_contours = cv2.cvtColor(np.array(source_img), cv2.COLOR_RGB2BGR)  # 将源图像转换为BGR格式以便在其上画出轮廓

# 在原图上画出轮廓
for idx, single_contour in enumerate(contours):
    posX, posY, width, height = cv2.boundingRect(single_contour)  # 计算轮廓的边界框
    border = 40  # 设定边界
    posX = max(0, posX - border)  # 计算新的x坐标
    width = width + 2 * border  # 计算新的宽度
    height = height + border  # 计算新的高度
    cv2.rectangle(img_with_contours, (posX, posY), (posX+width, posY+height), (0, 255, 0), 2)  # 在原图上画出边界框

# 显示处理过程中的各个步骤的图像
fig, axs = plt.subplots(1, 7, figsize=(35, 5))
axs[0].imshow(gray_img, cmap='gray')
axs[0].set_title('灰度图', size=15)
axs[0].axis('off')
axs[1].imshow(binary_img, cmap='gray')
axs[1].set_title('二值图', size=15)
axs[1].axis('off')
axs[2].imshow(eroded_img, cmap='gray')
axs[2].set_title('腐蚀图', size=15)
axs[2].axis('off')
axs[3].imshow(filtered_img, cmap='gray')
axs[3].set_title('膨胀图', size=15)
axs[3].axis('off')
axs[4].imshow(closed_img, cmap='gray')
axs[4].set_title('闭运算图', size=15)
axs[4].axis('off')
axs[5].imshow(edges_detected, cmap='gray')
axs[5].set_title('Canny边缘检测', size=15)
axs[5].axis('off')
axs[6].imshow(img_with_contours)
axs[6].set_title('带有轮廓的原图', size=15)
axs[6].axis('off')
plt.show()

if not os.path.exists('chars'):
    os.makedirs('chars')  # 如果不存在chars文件夹则创建

# 保存每个字符的图像
for idx, single_contour in enumerate(contours):
    posX, posY, width, height = cv2.boundingRect(single_contour)  # 计算轮廓的边界框
    border = 40  # 设定边界
    posX = max(0, posX - border)  # 计算新的x坐标
    width = width + 2 * border  # 计算新的宽度
    height = height + border  # 计算新的高度
    # 裁剪出字符图像
    single_char_img = gray_img[posY:posY+height, posX:posX+width]
    
    # 将numpy数组转换为PIL的Image对象
    single_char_img_pil = Image.fromarray(single_char_img)
    
    # 保存字符图像
    single_char_img_pil.save(f'chars/char_{idx}.jpg')